package com.yzq.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.ObjUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.yzq.common.Result;
import com.yzq.enums.BusinessType;
import com.yzq.enums.UserRole;
import com.yzq.exception.BusinessException;
import com.yzq.manager.auth.StpKit;
import com.yzq.model.dto.EmailRegisterRequest;
import com.yzq.model.dto.PhoneRegisterRequest;
import com.yzq.model.dto.UserLoginRequest;
import com.yzq.model.dto.user.UserAddRequest;
import com.yzq.model.dto.user.UserDeleteRequest;
import com.yzq.model.dto.user.UserQueryRequest;
import com.yzq.model.dto.user.UserUpdateRequest;
import com.yzq.model.entity.User;
import com.yzq.model.vo.UserVO;
import com.yzq.service.UserService;
import com.yzq.mapper.UserMapper;
import com.yzq.service.VerificationCodeService;
import com.yzq.utils.MD5Util;
import com.yzq.enums.ErrorCode;
import com.yzq.utils.ThrowUtils;
import lombok.extern.slf4j.Slf4j;
import org.jetbrains.annotations.NotNull;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.Date;

import static com.yzq.constant.UserConstant.USER_LOGIN_STATE;

/**
 * @author yezhi
 * @description 针对表【user(用户)】的数据库操作Service实现
 * @createDate 2025-06-29 07:25:29
 */
@Slf4j
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User>
        implements UserService {

    @Resource
    private UserMapper userMapper;

    @Resource
    private VerificationCodeService verificationCodeService;

    @Transactional(rollbackFor = Exception.class)
    @Override
    public Long emailRegister(EmailRegisterRequest emailRegisterRequest) {
        // 1. 后端获取用户的请求体
        String email = emailRegisterRequest.getEmail();
        String password = emailRegisterRequest.getPassword();
        String checkPassword = emailRegisterRequest.getCheckPassword();
        String verifyCode = emailRegisterRequest.getVerifyCode();

        // 2. 校验请求参数是否完整
        if (email == null || password == null || checkPassword == null || verifyCode == null) {
            throw new BusinessException(ErrorCode.BAD_REQUEST, "请求参数不完整");
        }

        // 3. 查看注册账号是否重复
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("email", email);
        User user = userMapper.selectOne(queryWrapper);
        if (user != null) {
            throw new BusinessException(ErrorCode.CONFLICT, "该邮箱已被注册");
        }

        // 4. 校验密码和确认密码
        if (!password.equals(checkPassword)) {
            throw new BusinessException(ErrorCode.BAD_REQUEST, "密码和确认密码不一致");
        }
        // 5. 校验验证码
        boolean verifyResult = verificationCodeService.verifyVerificationCode(email, BusinessType.REGISTER, verifyCode);
        if (!verifyResult) {
            throw new BusinessException(ErrorCode.BAD_REQUEST, "验证码校验失败");
        }

        // 6. 将用户密码进行MD5加密
        String encryptedPassword = MD5Util.encrypt(password);

        // 7. 保存用户信息
        User newUser = new User();
        newUser.setEmail(email);
        newUser.setUserAccount(email);
        newUser.setUserPassword(encryptedPassword);
        newUser.setUserRole(UserRole.USER.getCode());
        newUser.setUserName("普通用户");
        newUser.setCreateTime(new Date());
        newUser.setUpdateTime(newUser.getCreateTime());
        newUser.setEditTime(newUser.getCreateTime());
        int insertResult = userMapper.insert(newUser);
        if (insertResult != 1) {
            throw new BusinessException(ErrorCode.INTERNAL_SERVER_ERROR, "用户信息保存失败");
        }
        // 9. 返回用户id
        return Long.valueOf(newUser.getId());
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public Long phoneRegister(PhoneRegisterRequest phoneRegisterRequest) {
        // 1. 后端获取用户的请求体
        String phone = phoneRegisterRequest.getPhone();
        String password = phoneRegisterRequest.getPassword();
        String checkPassword = phoneRegisterRequest.getCheckPassword();
        String verifyCode = phoneRegisterRequest.getVerifyCode();

        // 2. 校验请求参数是否完整
        if (phone == null || password == null || checkPassword == null || verifyCode == null) {
            throw new BusinessException(ErrorCode.BAD_REQUEST, "请求参数不完整");
        }

        // 3. 查看注册账号是否重复
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("phone", phone);
        User user = userMapper.selectOne(queryWrapper);
        if (user != null) {
            throw new BusinessException(ErrorCode.CONFLICT, "该手机号已被注册");
        }

        // 4. 校验密码和确认密码
        if (!password.equals(checkPassword)) {
            throw new BusinessException(ErrorCode.BAD_REQUEST, "密码和确认密码不一致");
        }

        // 5. 校验验证码
        boolean verifyResult = verificationCodeService.verifyVerificationCode(phone, BusinessType.REGISTER, verifyCode);
        if (!verifyResult) {
            throw new BusinessException(ErrorCode.BAD_REQUEST, "验证码校验失败");
        }

        // 6. 将用户密码进行MD5加密
        String encryptedPassword = MD5Util.encrypt(password);

        // 7. 保存用户信息
        User newUser = new User();
        newUser.setPhone(phone);
        newUser.setUserAccount(phone);
        newUser.setUserRole(UserRole.USER.getCode());
        newUser.setUserName("普通用户");
        newUser.setUserPassword(encryptedPassword);
        newUser.setCreateTime(new Date());
        newUser.setUpdateTime(newUser.getCreateTime());
        newUser.setEditTime(newUser.getCreateTime());
        int insertResult = userMapper.insert(newUser);
        if (insertResult != 1) {
            throw new BusinessException(ErrorCode.INTERNAL_SERVER_ERROR, "用户信息保存失败");
        }

        // 8. 返回用户id
        return newUser.getId();
    }

    /**
     * 用户登录
     *
     * @param userLoginRequest 用户登录请求
     * @param request 请求
     * @return 用户信息
     */
    @Override
    public UserVO userLogin(UserLoginRequest userLoginRequest, HttpServletRequest request) {
        // 1. 验证登录请求
        if (userLoginRequest == null) {
            throw new BusinessException(ErrorCode.BAD_REQUEST);
        }
        String userAccount = userLoginRequest.getUserAccount();
        String userPassword = userLoginRequest.getUserPassword();

        // 校验账号密码格式
        if (!StringUtils.hasText(userAccount) || !StringUtils.hasText(userPassword)) {
            throw new BusinessException(ErrorCode.BAD_REQUEST, "账号或密码为空");
        }
        if (userAccount.length() < 4) {
            throw new BusinessException(ErrorCode.BAD_REQUEST, "账号长度过短");
        }
        if (userPassword.length() < 6) {
            throw new BusinessException(ErrorCode.BAD_REQUEST, "密码长度过短");
        }

        // 2. 查询数据库是否存在该用户
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("user_account", userAccount);
        User user = userMapper.selectOne(queryWrapper);

        // 用户不存在
        if (user == null) {
            throw new BusinessException(ErrorCode.USER_NOT_FOUND, "用户不存在");
        }

        // 3. 校验密码（MD5）
        String encryptedPassword = MD5Util.encrypt(userPassword);
        if (!encryptedPassword.equals(user.getUserPassword())) {
            throw new BusinessException(ErrorCode.BAD_REQUEST, "密码错误");
        }

        //4.对用户进行脱敏
        UserVO userVO = UserVO.toVO(user);

        //5. 记录登录态
        request.getSession().setAttribute(USER_LOGIN_STATE, userVO);

        //6. 记录登录态到 Sa-Token, 便于空间鉴权时使用，避免用户在空间内被其他用户所访问
        StpKit.SPACE.login(userVO.getId());
        StpKit.SPACE.getSession().set(USER_LOGIN_STATE, userVO);

        log.info("用户登录成功：{}", userVO);
        return userVO;
    }

    /**
     * 获取当前用户
     * @param request 请求
     * @return 当前用户
     */
    @Override
    public UserVO getCurrentUser(HttpServletRequest request) {
        //1. 判断是否登录
        Object userObj = request.getSession().getAttribute(USER_LOGIN_STATE);
        if (userObj == null) {
            throw new BusinessException(ErrorCode.FORBIDDEN_USER_NOT_LOGIN);
        }

        //2. 从数据库查询
        UserVO currentUser = (UserVO) userObj;
        Long id = currentUser.getId();
        User user = userMapper.selectById(id);
        if (user == null) {
            throw new BusinessException(ErrorCode.USER_NOT_FOUND);
        }
        return UserVO.toVO(user);
    }

    /**
     * 用户登出
     * @param request 请求
     * @return 是否登出成功
     */
    @Override
    public Boolean userLogout(HttpServletRequest request) {
        //1.判断是否登录
        Object userObj = request.getSession().getAttribute(USER_LOGIN_STATE);
        if (userObj == null) {
            throw new BusinessException(ErrorCode.FORBIDDEN_USER_NOT_LOGIN);
        }
        request.getSession().removeAttribute(USER_LOGIN_STATE);
        return true;
    }

    /**
     * 添加用户
     * @param userAddRequest 用户添加请求
     * @return 用户id
     */
    @Override
    public Long addUser(UserAddRequest userAddRequest) {
        if (userAddRequest == null) {
            throw new BusinessException(ErrorCode.BAD_REQUEST);
        }
        ThrowUtils.throwIf(StrUtil.hasBlank(userAddRequest.getUserName(), userAddRequest.getUserRole()),ErrorCode.BAD_REQUEST);
        if(userAddRequest.getPhone() == null && userAddRequest.getEmail() == null ) {
            throw new BusinessException(ErrorCode.BAD_REQUEST, "手机号和邮箱不能同时为空");
        }
        User user = new User();
        BeanUtil.copyProperties(userAddRequest, user);
        user.setCreateTime(new Date());
        user.setUpdateTime(user.getCreateTime());
        user.setEditTime(user.getCreateTime());
        // 设置账号
        if(StrUtil.isNotBlank(userAddRequest.getPhone())) {
            user.setUserAccount(userAddRequest.getPhone());
        } else {
            user.setUserAccount(userAddRequest.getEmail());
        }

        //查询是否已存在该用户
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("user_account", user.getUserAccount());
        User oldUser = userMapper.selectOne(queryWrapper);
        if (oldUser != null) {
            throw new BusinessException(ErrorCode.CONFLICT, "用户已存在");
        }
        final String USER_PASSWORD = "123456";
        String encryptedPassword = MD5Util.encrypt(USER_PASSWORD);
        user.setUserPassword(encryptedPassword);
        int insertResult = userMapper.insert(user);
        if (insertResult != 1) {
            throw new BusinessException(ErrorCode.INTERNAL_SERVER_ERROR, "用户信息保存失败");
        }
        return user.getId();
    }

    /**
     * 获取用户ById
     *
     * @param id 用户id
     * @return 用户信息
     */
    @Override
    public User getUserById(Long id) {
        if (id == null) {
            throw new BusinessException(ErrorCode.BAD_REQUEST);
        }
        User user = userMapper.selectById(id);
        if (user == null) {
            throw new BusinessException(ErrorCode.NOT_FOUND);
        }
        user.setUserPassword(null);
        return user;
    }

    /**
     * 分页获取用户列表
     * @param userQueryRequest 用户查询请求
     * @return 用户列表
     */
    @Override
    public Page<User> getUserList(UserQueryRequest userQueryRequest) {
        if (userQueryRequest == null) {
            throw new BusinessException(ErrorCode.BAD_REQUEST);
        }
        QueryWrapper<User> queryWrapper = getUserQueryWrapper(userQueryRequest);
        Page<User> page = new Page<>(userQueryRequest.getPageNum(), userQueryRequest.getPageSize());
        Page<User> userPage = userMapper.selectPage(page, queryWrapper);
        if (userQueryRequest.isSortEnabled()) {
            queryWrapper.orderBy(true, "ASC".equals(userQueryRequest.getSortOrder()), userQueryRequest.getSortField());
        }
        // 将获取到的用户列表中的密码置为null
        userPage.getRecords().forEach(user -> user.setUserPassword(null));
        return userPage;
    }

    /**
     * 获取查询条件
     * @param userQueryRequest 用户查询请求
     * @return 查询条件
     */
    private static @NotNull QueryWrapper<User> getUserQueryWrapper(UserQueryRequest userQueryRequest) {
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq(ObjUtil.isNotNull(userQueryRequest.getId()), "id", userQueryRequest.getId());
        queryWrapper.like(StrUtil.isNotBlank(userQueryRequest.getUserName()), "user_name", userQueryRequest.getUserName());
        queryWrapper.like(StrUtil.isNotBlank(userQueryRequest.getUserAccount()), "user_account", userQueryRequest.getUserAccount());
        queryWrapper.like(StrUtil.isNotBlank(userQueryRequest.getUserRole()), "user_role", userQueryRequest.getUserRole());
        queryWrapper.like(StrUtil.isNotBlank(userQueryRequest.getPhone()), "phone", userQueryRequest.getPhone());
        queryWrapper.like(StrUtil.isNotBlank(userQueryRequest.getEmail()), "email", userQueryRequest.getEmail());

        return queryWrapper;
    }

    /**
     * 删除用户
     * @param userDeleteRequest 用户删除请求
     * @return 是否删除成功
     */
    @Override
    public Boolean deleteUser(UserDeleteRequest userDeleteRequest) {
        if (userDeleteRequest == null) {
            throw new BusinessException(ErrorCode.BAD_REQUEST);
        }
        return userMapper.deleteById(userDeleteRequest.getId()) > 0;
    }

    /**
     * 更新用户
     * @param userUpdateRequest 用户更新请求
     * @return 是否更新成功
     */
    @Override
    public Boolean updateUser(UserUpdateRequest userUpdateRequest) {
        if (userUpdateRequest == null) {
            throw new BusinessException(ErrorCode.BAD_REQUEST);
        }
        ThrowUtils.throwIf(StrUtil.hasBlank(userUpdateRequest.getUserName(), userUpdateRequest.getUserRole()),ErrorCode.BAD_REQUEST);
        User user = new User();
        BeanUtil.copyProperties(userUpdateRequest, user);
        user.setUpdateTime(new Date());
        return userMapper.updateById(user) > 0;
    }

    /**
     * 判断是否为管理员
     * @param request 请求
     * @return 是否为管理员
     */
    @Override
    public boolean isAdmin(HttpServletRequest request) {
        // 1. 获取当前登录用户
        Object userObj = request.getSession().getAttribute(USER_LOGIN_STATE);
        UserVO user = (UserVO) userObj;
        if (user == null || user.getUserRole() == null) {
            return false;
        }
        return UserRole.ADMIN.getCode().equals(user.getUserRole());
    }

    @Override
    public boolean isAdmin(UserVO userVO) {
        return UserRole.ADMIN.getCode().equals(userVO.getUserRole());
    }

    /**
     * 更新当前用户
     * @param userUpdateRequest 用户更新请求
     * @param request 请求
     * @return 是否更新成功
     */
    @Override
    public Result<String> updateCurrentUser(UserUpdateRequest userUpdateRequest, HttpServletRequest request) {
        ThrowUtils.throwIf(userUpdateRequest == null, ErrorCode.BAD_REQUEST);
        ThrowUtils.throwIf(ObjUtil.isNotNull(userUpdateRequest.getId()),ErrorCode.BAD_REQUEST, "非法查询");
        UserVO currentUser = this.getCurrentUser(request);
        Long id = currentUser.getId();
        User userById = this.getUserById(id);
        userById.setUserName(userUpdateRequest.getUserName());
        userById.setUserProfile(userUpdateRequest.getUserProfile());
        userById.setEmail(userUpdateRequest.getEmail());
        userById.setPhone(userUpdateRequest.getPhone());
        userById.setEditTime(new Date());
        return userMapper.updateById(userById) > 0 ? Result.success("更新成功") : Result.error(ErrorCode.OPERATION_ERROR);
    }
}